package cn.zjyj.module.zjyj.service.riskidentify;

import cn.hutool.core.collection.CollUtil;
import cn.zjyj.module.system.dal.dataobject.user.AdminUserDO;
import cn.zjyj.module.system.service.user.AdminUserService;
import cn.zjyj.module.zjyj.controller.admin.riskapplyrecord.vo.RiskAssessmentApplyRecordPageReqVO;
import cn.zjyj.module.zjyj.controller.admin.riskapplyrecord.vo.RiskAssessmentApplyRecordRespVO;
import cn.zjyj.module.zjyj.controller.admin.riskidentifytarget.vo.RiskIdentifyTargetSaveReqVO;
import cn.zjyj.module.zjyj.controller.admin.riskidentifytargetcontent.vo.RiskIdentifyTargetContentSaveReqVO;
import cn.zjyj.module.zjyj.dal.dataobject.riskapplyrecord.RiskAssessmentApplyRecordDO;
import cn.zjyj.module.zjyj.dal.dataobject.riskidentifyinstance.RiskIdentifyDeviceInstanceBo;
import cn.zjyj.module.zjyj.dal.dataobject.riskidentifyinstance.RiskIdentifyInstanceDO;
import cn.zjyj.module.zjyj.dal.dataobject.riskidentifytarget.RiskIdentifyTargetDO;
import cn.zjyj.module.zjyj.dal.dataobject.riskidentifytargetcontent.RiskIdentifyTargetContentDO;
import cn.zjyj.module.zjyj.dal.mysql.riskapplyrecord.RiskAssessmentApplyRecordMapper;
import cn.zjyj.module.zjyj.dal.mysql.riskidentifyinstance.RiskIdentifyInstanceMapper;
import cn.zjyj.module.zjyj.dal.mysql.riskidentifytarget.RiskIdentifyTargetMapper;
import cn.zjyj.module.zjyj.dal.mysql.riskidentifytargetcontent.RiskIdentifyTargetContentMapper;
import cn.zjyj.module.zjyj.service.riskapplyrecord.RiskAssessmentApplyRecordService;
import cn.zjyj.module.zjyj.service.riskidentifyinstance.RiskIdentifyInstanceService;
import cn.zjyj.module.zjyj.service.risklist.RiskListService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;

import cn.zjyj.module.zjyj.controller.admin.riskidentify.vo.*;
import cn.zjyj.module.zjyj.dal.dataobject.riskidentify.RiskIdentifyDO;
import cn.zjyj.framework.common.common.pojo.PageResult;
import cn.zjyj.framework.common.common.util.object.BeanUtils;

import cn.zjyj.module.zjyj.dal.mysql.riskidentify.RiskIdentifyMapper;

import static cn.zjyj.framework.common.common.exception.util.ServiceExceptionUtil.exception;
import static cn.zjyj.module.zjyj.enums.ErrorCodeConstants.*;

/**
 * 风险辨识主 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
public class RiskIdentifyServiceImpl implements RiskIdentifyService {

    @Resource
    private RiskIdentifyMapper riskIdentifyMapper;

    @Resource
    RiskListService riskListService;

    @Resource
    RiskAssessmentApplyRecordMapper riskAssessmentApplyRecordMapper;

    @Resource
    RiskAssessmentApplyRecordService riskAssessmentApplyRecordService;

    @Resource
    RiskIdentifyInstanceMapper riskIdentifyInstanceMapper;

    @Resource
    RiskIdentifyTargetMapper riskIdentifyTargetMapper;

    @Resource
    RiskIdentifyTargetContentMapper riskIdentifyTargetContentMapper;

    @Resource
    RiskIdentifyInstanceService riskIdentifyInstanceService;
    @Resource
    AdminUserService adminUserService;


    @Override
    public Long createRiskIdentify(RiskIdentifySaveReqVO createReqVO) {
        // 插入
        if (createReqVO.getId() == null) {
            RiskIdentifyDO riskIdentifyDO = riskIdentifyMapper.selectFirstOne(RiskIdentifyDO::getRiskTypeInfoId, createReqVO.getRiskTypeInfoId(), RiskIdentifyDO::getRiskType, createReqVO.getRiskType());
            if (riskIdentifyDO == null) {
                // 插入
                RiskIdentifyDO riskIdentify = BeanUtils.toBean(createReqVO, RiskIdentifyDO.class);
                riskIdentifyMapper.insert(riskIdentify);
                createReqVO.setId(riskIdentify.getId());
            } else {
                createReqVO.setId(riskIdentifyDO.getId());
            }
        }
        // 风险实例表
        RiskIdentifyInstanceDO riskIdentifyInstance = RiskIdentifyInstanceDO.builder()
                .identifyId(createReqVO.getId()).instanceId(createReqVO.getInstanceId()).build();
        riskIdentifyInstanceMapper.insert(riskIdentifyInstance);

        createReqVO.getIdentifyTargets().stream().forEach(target -> {
            RiskIdentifyTargetDO build = RiskIdentifyTargetDO.builder()
                    .identifyId(createReqVO.getId())
                    .identifyInstanceId(riskIdentifyInstance.getId())
                    .riskTarget(target.getRiskTarget())
                    .build();
            riskIdentifyTargetMapper.insert(build);
            target.getContents().stream().forEach(content -> {
                RiskIdentifyTargetContentDO riskIdentifyTargetContentDO = BeanUtils.toBean(content, RiskIdentifyTargetContentDO.class);
                riskIdentifyTargetContentDO.setIdentifyId(createReqVO.getId());
                riskIdentifyTargetContentDO.setIdentifyInstanceId(riskIdentifyInstance.getId());
                riskIdentifyTargetContentDO.setRiskTargetId(build.getId());
                riskIdentifyTargetContentMapper.insert(riskIdentifyTargetContentDO);
            });
        });
        return createReqVO.getId();
    }

    @Override
    public void updateRiskIdentify(RiskIdentifySaveReqVO updateReqVO) {
        // 校验存在
        validateRiskIdentifyExists(updateReqVO.getId());

        RiskIdentifyInstanceDO identifyInstanceDO = riskIdentifyInstanceMapper.selectFirstOne(RiskIdentifyInstanceDO::getInstanceId, updateReqVO.getInstanceId(),
                RiskIdentifyInstanceDO::getIdentifyId, updateReqVO.getId(), RiskIdentifyInstanceDO::getIdentifyId, updateReqVO.getId());
        List<Long> targetIds = updateReqVO.getIdentifyTargets().stream().filter(item -> item.getId() != null).map(RiskIdentifyTargetSaveReqVO::getId).collect(Collectors.toList());
        LambdaQueryWrapper<RiskIdentifyTargetDO> targetWrapper = new LambdaQueryWrapper<>();
        targetWrapper.eq(RiskIdentifyTargetDO::getIdentifyId, updateReqVO.getId())
                .eq(RiskIdentifyTargetDO::getIdentifyInstanceId, updateReqVO.getInstanceId());
        if (CollUtil.isNotEmpty(targetIds)) {
            targetWrapper.notIn(RiskIdentifyTargetDO::getId, targetIds);
        }
        riskIdentifyTargetMapper.delete(targetWrapper);

        updateReqVO.getIdentifyTargets().stream().forEach(target -> {
            RiskIdentifyTargetDO riskIdentifyTarget = BeanUtils.toBean(target, RiskIdentifyTargetDO.class);
            riskIdentifyTargetMapper.insertOrUpdate(riskIdentifyTarget);
            // 删除原来的风险对象
            LambdaQueryWrapper<RiskIdentifyTargetContentDO> contentWrapper = new LambdaQueryWrapper<>();
            contentWrapper.eq(RiskIdentifyTargetContentDO::getIdentifyId, updateReqVO.getId())
                    .eq(RiskIdentifyTargetContentDO::getIdentifyInstanceId, identifyInstanceDO.getId())
                    .eq(RiskIdentifyTargetContentDO::getRiskTargetId, target.getId());
            List<Long> contentIds = target.getContents().stream().filter(item -> item.getId() != null).map(RiskIdentifyTargetContentSaveReqVO::getId).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(contentIds)) {
                contentWrapper.notIn(RiskIdentifyTargetContentDO::getId, contentIds);
            }
            riskIdentifyTargetContentMapper.delete(contentWrapper);
            target.getContents().stream().forEach(content -> {
                RiskIdentifyTargetContentDO riskIdentifyTargetContentDO = BeanUtils.toBean(content, RiskIdentifyTargetContentDO.class);
                riskIdentifyTargetContentDO.setIdentifyId(updateReqVO.getId());
                riskIdentifyTargetContentDO.setRiskTargetId(target.getId());
                riskIdentifyTargetContentDO.setIdentifyInstanceId(identifyInstanceDO.getId());
                riskIdentifyTargetContentMapper.insertOrUpdate(riskIdentifyTargetContentDO);
            });

        });
    }

    @Override
    public void deleteRiskIdentify(Long id) {
        // 校验存在
        validateRiskIdentifyExists(id);
        // 删除
        riskIdentifyMapper.deleteById(id);
    }

    @Override
    public void deleteRiskIdentifyListByIds(List<Long> ids) {
        // 校验存在
        validateRiskIdentifyExists(ids);
        // 删除
        riskIdentifyMapper.deleteByIds(ids);
    }

    private void validateRiskIdentifyExists(List<Long> ids) {
        List<RiskIdentifyDO> list = riskIdentifyMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(RISK_IDENTIFY_NOT_EXISTS);
        }
    }

    private void validateRiskIdentifyExists(Long id) {
        if (riskIdentifyMapper.selectById(id) == null) {
            throw exception(RISK_IDENTIFY_NOT_EXISTS);
        }
    }

    @Override
    public RiskIdentifyRespVO getRiskIdentify(Long id) {
        RiskIdentifyDO riskIdentifyDO = riskIdentifyMapper.selectById(id);
        RiskIdentifyRespVO item = BeanUtils.toBean(riskIdentifyDO, RiskIdentifyRespVO.class);
        if (item == null) {
            throw exception(RISK_IDENTIFY_NOT_EXISTS);
        }
        item.setRiskInfoName(riskListService.getRiskName(item.getRiskType(), item.getRiskTypeInfoId()));
//        List<RiskIdentifyObjectWithContentRespVO> byIdentifyId = riskIdentifyObjectService.getByIdentifyId(item.getId());
//        item.setIdentifyObjects(byIdentifyId);
        return item;
    }

    @Override
    public PageResult<RiskIdentifyRespVO> getRiskIdentifyPage(RiskIdentifyPageReqVO pageReqVO) {
        PageResult<RiskIdentifyDO> riskIdentifyDOPageResult = riskIdentifyMapper.selectPage(pageReqVO);
        PageResult<RiskIdentifyRespVO> results = BeanUtils.toBean(riskIdentifyDOPageResult, RiskIdentifyRespVO.class);
        if (CollUtil.isEmpty(results.getList())) {
            return results;
        }
        results.getList().stream().forEach(item -> {
            item.setRiskInfoName(riskListService.getRiskName(item.getRiskType(), item.getRiskTypeInfoId()));
            item.setInstances(riskIdentifyInstanceService.getIdentifyInstanceWithTarget(item.getId()));
        });
        return results;
    }

    @Override
    public PageResult<RiskIdentifyApplyRecordRespVO> getRiskIdentifyApplyRecordPage(RiskIdentifyApplyRecordPageReqVO pageReqVO) {
        PageResult<RiskAssessmentApplyRecordRespVO> riskApplyRecordPage = riskAssessmentApplyRecordService.getRiskApplyRecordPage(BeanUtils.toBean(pageReqVO, RiskAssessmentApplyRecordPageReqVO.class));
        if (CollUtil.isEmpty(riskApplyRecordPage.getList())) {
            return new PageResult<>();
        }
        List<Long> identifyIds = riskApplyRecordPage.getList().stream().map(RiskAssessmentApplyRecordRespVO::getIdentifyId).collect(Collectors.toList());
        List<RiskIdentifyDO> riskIdentifyDOS = riskIdentifyMapper.selectBatchIds(identifyIds);


//        RiskIdentifyPageReqVO identifyPageReqVO = BeanUtils.toBean(pageReqVO, RiskIdentifyPageReqVO.class);
//        identifyPageReqVO.setStatus(1);
//        PageResult<RiskIdentifyDO> riskIdentifyDOPageResult = riskIdentifyMapper.selectPage(identifyPageReqVO);
//        if (CollUtil.isEmpty(riskIdentifyDOPageResult.getList())) {
//            return new PageResult<>();
//        }
        List<RiskIdentifyDeviceInstanceBo> deviceInstanceIdentify = riskIdentifyInstanceMapper.getDeviceInstanceIdentify(identifyIds);

        // 取ownerId
        List<Long> ownerIds = deviceInstanceIdentify.stream().map(RiskIdentifyDeviceInstanceBo::getOwnerId).distinct().collect(Collectors.toList());
        Map<Long, AdminUserDO> userMap = adminUserService.getUserMap(ownerIds);

        PageResult<RiskIdentifyApplyRecordRespVO> bean = BeanUtils.toBean(riskApplyRecordPage, RiskIdentifyApplyRecordRespVO.class);
        bean.getList().stream().forEach(item -> {
            riskIdentifyDOS.stream().filter(identify -> item.getIdentifyId().equals(identify.getId())).findFirst().ifPresent(identifyDO -> {
                item.setRiskType(identifyDO.getRiskType());
                item.setRiskTypeInfoId(identifyDO.getRiskTypeInfoId());
            });
            item.setRiskInfoName(riskListService.getRiskName(item.getRiskType(), item.getRiskTypeInfoId()));
            List<RiskIdentifyDeviceInstanceBo> collect = deviceInstanceIdentify.stream().filter(instance -> item.getId().equals(instance.getIdentifyId())).map(instance -> {
                AdminUserDO adminUserDO = userMap.get(instance.getOwnerId());
                instance.setOwnerName(adminUserDO == null ? "" : adminUserDO.getNickname());
                return instance;
            }).collect(Collectors.toList());
            item.setDoneSize(collect.stream().filter(instance -> instance.getStatus() != 0).count());
            item.setTotalSize((long) collect.size());
            item.setInstances(collect);
        });
        return bean;
    }

    @Override
    public void applyAssessment(Long id) {
        RiskIdentifyDO identify = riskIdentifyMapper.selectById(id);
        identify.setStatus(1);
        riskIdentifyMapper.updateById(identify);
        RiskAssessmentApplyRecordDO record = RiskAssessmentApplyRecordDO.builder()
                .identifyId(id)
                .build();
        riskAssessmentApplyRecordMapper.insert(record);
    }
}